#ifndef __U2Viewport_H__
#define __U2Viewport_H__


#include "U2PreRequest.h"
#include "U2MemoryAllocatorConfig.h"
#include "U2ColourValue.h"
#include "U2Common.h"
#include "U2Vector2.h"
#include "U2Frustum.h"




U2EG_NAMESPACE_BEGIN



class U2Camera;
class U2RenderTarget;


class _U2Share U2Viewport : public ViewportAlloc
{
public:
    /** Listener interface so you can be notified of U2Viewport changes. */
    class _U2Share Listener
    {
    public:
        virtual ~Listener() {}

        /** Notification of when a new camera is set to target listening U2Viewport. */
        virtual void viewportCameraChanged(U2Viewport* viewport) {}

        /** Notification of when target listening U2Viewport's dimensions changed. */
        virtual void viewportDimensionsChanged(U2Viewport* viewport) {}

        /** Notification of when target listening U2Viewport's is destroyed. */
        virtual void viewportDestroyed(U2Viewport* viewport) {}
    };

public:
   /** The usual constructor.
    @param
        cam Pointer to a camera to be the source for the image.
    @param
        target Pointer to the render target to be the destination
        for the rendering.
    @param
        left
    @param
        top
    @param
        width
    @param
        height
        Dimensions of the viewport, expressed as a value between
        0 and 1. This allows the dimensions to apply irrespective of
        changes in the target's size: e.g. to fill the whole area,
        values of 0,0,1,1 are appropriate.
    @param
        ZOrder Relative Z-order on the target. Lower = further to
        the front.
    */
    U2Viewport(
        U2Camera* camera,
        U2RenderTarget* target,
        u2real left, u2real top,
        u2real width, u2real height,
        int ZOrder);

    /** Default destructor.
    */
    virtual ~U2Viewport();

    /** Retrieves a pointer to the render target for this viewport.
    */
    U2RenderTarget* getTarget(void) const;
    /** Retrieves a pointer to the camera for this viewport.
    */
    U2Camera* getCamera(void) const;
    /** Sets the camera to use for rendering to this viewport. */
    void setCamera(U2Camera* cam);
    /** Gets the Z-Order of this viewport. */
	int getZOrder(void) const;
	/** Gets one of the relative dimensions of the viewport,
        a value between 0.0 and 1.0.
    */
    u2real getLeft(void) const;
    /** Gets one of the relative dimensions of the viewport, a value
        between 0.0 and 1.0.
    */
    u2real getTop(void) const;
    /** Gets one of the relative dimensions of the viewport, a value
        between 0.0 and 1.0.
    */
    u2real getWidth(void) const;
    /** Gets one of the relative dimensions of the viewport, a value
        between 0.0 and 1.0.
    */
    u2real getHeight(void) const;
    /** Gets one of the actual dimensions of the viewport, a value in
        pixels.
    */
    int getActualLeft(void) const;
    /** Gets one of the actual dimensions of the viewport, a value in
        pixels.
    */
    int getActualTop(void) const;
    /** Gets one of the actual dimensions of the viewport, a value in
        pixels.
    */
    int getActualWidth(void) const;
    /** Gets one of the actual dimensions of the viewport, a value in
        pixels.
    */
    int getActualHeight(void) const;
    /** Sets the dimensions (after creation).
    @param
        left
    @param
        top
    @param
        width
    @param
        height Dimensions relative to the size of the target,
        represented as real values between 0 and 1. i.e. the full
        target area is 0, 0, 1, 1.
    */
    void setDimensions(u2real left, u2real top, u2real width, u2real height);
    /** Sets the initial background colour of the viewport (before
        rendering).
    */
    void setBackgroundColour(const U2ColourValue& colour);
    /** Gets the background colour.
    */
    const U2ColourValue& getBackgroundColour(void) const;
	/** Sets the initial depth buffer value of the viewport (before
        rendering). Default is 1
    */
    void setDepthClear( u2real depth );
    /** Gets the default depth buffer value to which the viewport is cleared.
    */
    u2real getDepthClear(void) const;
    /** Determines whether to clear the viewport before rendering.
	@remarks
		You can use this method to set which buffers are cleared
		(if any) before rendering every frame.
    @param clear Whether or not to clear any buffers
	@param buffers One or more values from FrameBufferType denoting
		which buffers to clear, if clear is set to true. Note you should
		not clear the stencil buffer here unless you know what you're doing.
     */
    void setClearEveryFrame(bool clear, unsigned int buffers = FBT_COLOUR | FBT_DEPTH);
    /** Determines if the viewport is cleared before every frame.
    */
    bool getClearEveryFrame(void) const;
	/** Gets which buffers are to be cleared each frame. */
    unsigned int getClearBuffers(void) const;
	/** Sets whether this viewport should be automatically updated 
		if Ogre's rendering loop or RenderTarget::update is being used.
    @remarks
        By default, if you use Ogre's own rendering loop (Root::startRendering)
        or call RenderTarget::update, all viewports are updated automatically.
        This method allows you to control that behaviour, if for example you 
		have a viewport which you only want to update periodically.
    @param autoupdate If true, the viewport is updated during the automatic
        render loop or when RenderTarget::update() is called. If false, the 
        viewport is only updated when its update() method is called explicitly.
    */
	void setAutoUpdated(bool autoupdate);
	/** Gets whether this viewport is automatically updated if 
		Ogre's rendering loop or RenderTarget::update is being used.
    */
	bool isAutoUpdated() const;
	/** Access to actual dimensions (based on target size).
    */
    void getActualDimensions(int &left, int &top, int &width, int &height ) const;
    bool _isUpdated(void) const;
    void _clearUpdatedFlag(void);
	/** Sets a per-viewport visibility mask.
	@remarks
		The visibility mask is a way to exclude objects from rendering for
		a given viewport. For each object in the frustum, a check is made
		between this mask and the objects visibility flags 
		(@see MovableObject::setVisibilityFlags), and if a binary 'and'
		returns zero, the object will not be rendered.
	*/
	void setVisibilityMask(u2uint32 mask) { mVisibilityMask = mask; }
	/** Gets a per-viewport visibility mask.
	@see Viewport::setVisibilityMask
	*/
	u2uint getVisibilityMask(void) const { return mVisibilityMask; }

    /** Convert oriented input point coordinates to screen coordinates. */
    void pointOrientedToScreen(const U2Vector2 &v, int orientationMode, U2Vector2 &outv);
    void pointOrientedToScreen(u2real orientedX, u2real orientedY, int orientationMode,
        u2real &screenX, u2real &screenY);

    /// Add a listener to this camera
    void addListener(Listener* l);
    /// Remove a listener to this camera
    void removeListener(Listener* l);

    /** Set the orientation mode of the viewport.
    */
    void setOrientationMode(OrientationMode orientationMode, bool setDefault = true);
    /** Get the orientation mode of the viewport.
    */
    OrientationMode getOrientationMode() const;
    /** Set the initial orientation mode of viewports.
    */
    static void setDefaultOrientationMode(OrientationMode orientationMode);
    /** Get the initial orientation mode of viewports.
    */
    static OrientationMode getDefaultOrientationMode();

    /** Gets the number of rendered faces in the last update.
    */
    unsigned int _getNumRenderedFaces(void) const;
    /** Gets the number of rendered batches in the last update.
    */
    unsigned int _getNumRenderedBatches(void) const;

    /** Notifies the viewport of a possible change in dimensions.
    @remarks
        Used by the target to update the viewport's dimensions
        (usually the result of a change in target size).
    @note
        Internal use by Ogre only.
    */
    void _updateDimensions(void);
    /** Instructs the viewport to updates its contents.
    */
    void update(void);


protected:

    U2Camera            *mCamera;
    U2RenderTarget      *mTarget;
    // Relative dimensions, irrespective of target dimensions (0..1)
    float               mRelLeft, mRelTop, mRelWidth, mRelHeight;
    // Actual dimensions, based on target dimensions
    int                 mActLeft, mActTop, mActWidth, mActHeight;
    /// ZOrder
    int                 mZOrder;
    /// Background options
    U2ColourValue       mBackColour;
    u2real              mDepthClearValue;
    bool                mClearEveryFrame;
    unsigned int        mClearBuffers;
    bool                mUpdated;
    /// Automatic rendering on/off
    bool                mIsAutoUpdated;
    u2uint32            mVisibilityMask;

    /// Viewport orientation mode
    OrientationMode         mOrientationMode;
    static OrientationMode  mDefaultOrientationMode;

    typedef std::vector<Listener*>      ListenerList;
    ListenerList        mListeners;
};


U2EG_NAMESPACE_END


#endif
